Welcome back. So, we've already covered inheritance,
but it's worth talking about when we actually want to
inherit and how we want to inherit at times.
So, in general, the way that Python uses
inheritance is that let's suppose that we have a superclass.
So, I'm going to represent classes by this factory.
I think that factory is a good metaphor for classes,
a factory for constructing instances.
So, let's say that this red factory represents a superclass.
The superclass is the class that we're inheriting from.
Let's suppose that this blue factory represents a subclass.
So, the subclass inherits from the superclass.
I'm going to represent that just by having this little red dot here,
and that's like a line representing that we remember
that this subclass is inherited from that superclass.
Then, we of course have instances.
So, you might have an instance.
Let's suppose that this instances of the subclass.
I have this blue dot here to represent that Python remembers
that the instance is an instance of the subclass.
Now, whenever Python is looking for any method or instance variables,
it's always first going to look in the instance.
So, it's first going to look inside of the instance,
and it's going to ask does the instance have that thing?
If it doesn't, then it's going to look inside of
that instances class and it's going to ask
does that instances class have that instance variable or method?
If it doesn't, then it's then going to look into the superclass.
In Python, that's just how superclasses work.
By adding this extra layer of
looking at the superclass for things that are missing in the subclass,
what we do is we inherit everything that the superclass has and more.
So, this gets to the question of,
"When should we actually inherit from a superclass?"
Well, you should only inherit if
your subclass should have absolutely everything that the superclass has,
plus more or maybe plus some small modification.
So, let's go over an example of this.
So, let's suppose that I want to represent books in the library,
and let's suppose that we have two kinds of books.
We have paper books and we have ebooks.
So, the way that I would represent that in classes,
is I would have one superclass for book.
So, I'd say class book,
and every book is going to have a title and an author.
So, I'll say def_init,
and that's going to take in a title and an author.
Then I'm just going to set self.title,.title equals title, self.author equals author.
Let's suppose that we have this _str method as well,
and we're going to return title by author.
Okay, so now I have this book class.
I can create a new book.
So, I'll say, myBook equals a new Book.
Let's suppose that the title is
The Odyssey by Homer.
Then if I print out myBook,
then I'll see that my book is The Odyssey by Homer.
Let me actually add quotation marks around this when we print out the book title.
Okay, now let's suppose that a library can have two kinds of books.
Let's suppose that it can have ebooks and paper books.
So, both ebooks and paper books have everything that a book has plus more.
In the case of a paper book,
maybe we have a number of pages.
So, I'll say class PaperBook inherits from Book.
I'm going to have a constructor that takes in a title, author, and numPages.
Then I'm going to call the Book constructor.
So, I'll say, book._init with self, title, and author.
Then I'm going to assign an instance variable numPages.
So, I'll say self.numPages equals numPages.
So, that's a paper book.
Now, let's suppose that an electronic book doesn't have pages,
but it has a file size,
like three megabytes, five megabytes.
Hopefully not a gigabyte for a book,
but it has some size.
So, I'll say class EBook inherits from Book.
So, just like a book,
an e-book is going to have a title and an author.
I'll say def_init_ self, title, author.
Then instead of numPages, it has size.
Again, that's going to be the number of megabytes that this ebook takes up.
So, I'll say Book.init self, title, and author.
I'll say self.size equals size.
Okay. So, now let's say that my book is
an e-book with The Odyssey by Homer and let's say that it's two megabytes.
So, if I print out my ebook,
then I can see that it's still The Odyssey by Homer.
If I print out my book.size,
then I can see that it's two megabytes.
If this is instead a paper book,
so let's suppose that I also have a paper copy of this book,
myPaperBook equals new PaperBook,
The Odyssey by Homer,
and let's say that it has 500 pages.
I can see that myPaperBook.size.
It doesn't have size,
instead it has numPages.
Paper books don't have size, they have numPages.
So, you can see that myPaperBook.numPages is 500.
So, in this example,
we wanted to create paper book and ebook as separate subclasses because in this case,
a paper book has everything that a book has.
So, in this case, a paper book has a title and an author,
and so does ebook.
So, ebook has everything that a book has.
So, it has title and author and paper book also has this additional thing,
numPages and e-book has this additional thing bio size.
So, that's when you want to inherit.
When you want to have a subclass that has everything that the superclass has, plus more.
When you don't want to inherit,
is when you want to contain another class within a class.
So, let's go through an example.
So, let's suppose that I don't want these books to exist in isolation.
Let's say that I want to have a library class and libraries are going to contain books.
So, what I'm going to do,
is I'm going to say,
class library and every library has some fixed number of books.
So, I'll represent that by saying def_init.
So, I'm going to say that every library starts off with zero books.
So, I'll say self.books is an empty list.
Then we can add books to our library catalog.
So, I'll say def addBook self, and then book.
Here, book is going to be an instance of book.
So, whether it's a book,
a paper book or an ebook.
What we do is,
we add that book to our list of books.
So, I'll say self.books.append(book).
I'll say def getSize.
This is going to return the number of books that we have.
So, I'll return the length of self.book.
I'll actually give this a clear name, getNumBooks.
Okay, so the important point that I want to highlight here is that,
even though there's some relationship between library and this book classes,
in that a library contains a list of books,
we didn't want to inherit from book or we didn't want book to inherit
from library because it's not that a library has everything that a book has,
it doesn't, or that a book has everything library has, it doesn't either.
It's just that libraries contain books.
So, rather than inheriting from books,
I created a separate instance variable
to actually contain this list of books that we have.
So, this is an example of what's called composition.
So, a library contains or is composed of a list of books,
but rather than inheriting from the book class,
then we want to have a list of books as our instance variable.
So, let's see our class in action.
So, let's suppose that I have the Ann Arbor District Library,
aadl equals a new library and I say
aadl.addBook(myBook), and aadl.addBook (myPaperBook).
Now, if I print out aadl.getNumBooks,
then I'm going to see that my District Library has two books.
That's all for now, until next time.